package cn.xiaohuodui.util.alioss;

import cn.xiaohuodui.config.AliOssConfig;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.crypto.dsig.SignatureMethod;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

import static com.aliyun.oss.common.utils.DateUtil.formatIso8601Date;
import static com.aliyuncs.auth.AcsURLEncoder.percentEncode;

/**
 * 阿里OSS文件上传类
 *
 * @author Fang
 * @create 2017-03-29 下午2:02
 */
@Component
public class AliOssUploader {

    @Autowired
    AliOssConfig aliOssConfig;

    private static final String STS_API_VERSION = "2015-04-01";
    private static final String ENCODE_TYPE = "UTF-8";

    /**
     * 签名URL授权的上传和表单上传，忽略函数名，
     * <p>
     * {@link https://help.aliyun.com/document_detail/31839.html?spm=5176.doc31827.6.572.6tm1LZ}
     *
     * @param bucketType 0 图片  1 视频
     * @return
     */
    public Map generateUrl(int bucketType) {
        // 上传目录在可以在后台给定，但是前台比较方便
        String dir = "";
        String host = "http://" + getBucketName(bucketType) + "." + "oss-" + aliOssConfig.getRegion() + ".aliyuncs.com";
        OSSClient client = new OSSClient(aliOssConfig.getEndpoint(), aliOssConfig.getAccessKeyId(), aliOssConfig.getAccessKeySecret());
        Map<String, String> respMap = null;
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = client.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = client.calculatePostSignature(postPolicy);

            respMap = new LinkedHashMap<String, String>();
            respMap.put("accessid", aliOssConfig.getAccessKeyId());
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            //respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));


        } catch (Exception e) {
            e.printStackTrace();
        }

        return respMap;
    }

    /**
     * 转码后的视频信息查询
     * <p></p>
     * {@link https://help.aliyun.com/document_detail/44459.html?spm=5176.doc44473.6.648.Kq39SE}
     *
     * @param mediaId
     * @return
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    public String generateVideoQueryURL(String mediaId) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
        final String HTTP_METHOD = "GET";
        Map<String, String> parameterMap = new HashMap<String, String>();
        // 加入请求公共参数
        parameterMap.put("Action", "SearchTemplate");
        parameterMap.put("Version", "2014-06-18");
        //parameterMap.put("AccessKeyId", "LTAIJWU1gYbVZANx"); //此处请替换成您自己的AccessKeyId
        parameterMap.put("AccessKeyId", aliOssConfig.getAccessKeyId()); //此处请替换成您自己的AccessKeyId
        //parameterMap.put("Timestamp", "2015-05-14T09:03:45Z");//此处将时间戳固定只是测试需要，这样此示例中生成的签名值就不会变，方便您对比验证，可变时间戳的生成需要用下边这句替换
        parameterMap.put("Timestamp", formatIso8601Date(new Date()));
        parameterMap.put("SignatureMethod", "HMAC-SHA1");
        parameterMap.put("SignatureVersion", "1.0");
        //parameterMap.put("SignatureNonce", "4902260a-516a-4b6a-a455-45b653cf6150");//此处将唯一随机数固定只是测试需要，这样此示例中生成的签名值就不会变，方便您对比验证，可变唯一随机数的生成需要用下边这句替换
        parameterMap.put("SignatureNonce", UUID.randomUUID().toString());
        parameterMap.put("Format", "JSON");
        // 加入方法特有参数
        parameterMap.put("PageSize", "2");
        // 查询参数
        parameterMap.put("Action", "QueryMediaList");
        //parameterMap.put("MediaIds", "c0d93541f2524a57bcb5f14f6e73aea3");
        parameterMap.put("MediaIds", mediaId);
        parameterMap.put("IncludePlayList", "true");
        parameterMap.put("IncludeSnapshotList", "true");
        parameterMap.put("IncludeMediaInfo", "true");
        // 对参数进行排序
        List<String> sortedKeys = new ArrayList<String>(parameterMap.keySet());
        Collections.sort(sortedKeys);
        // 生成stringToSign字符
        final String SEPARATOR = "&";
        final String EQUAL = "=";
        StringBuilder stringToSign = new StringBuilder();
        stringToSign.append(HTTP_METHOD).append(SEPARATOR);
        stringToSign.append(percentEncode("/")).append(SEPARATOR);
        StringBuilder canonicalizedQueryString = new StringBuilder();
        for (String key : sortedKeys) {
            // 此处需要对key和value进行编码
            String value = parameterMap.get(key);
            canonicalizedQueryString.append(SEPARATOR).append(percentEncode(key)).append(EQUAL).append(percentEncode(value));
        }
        // 此处需要对canonicalizedQueryString进行编码
        stringToSign.append(percentEncode(canonicalizedQueryString.toString().substring(1)));

        final String ALGORITHM = "HmacSHA1";
        final String secret = aliOssConfig.getAccessKeySecret();//此处请替换成您的AccessKeySecret
        //final String secret = "MppfnHMA7LaokAUnvJsaYRnSpEj4wW";//此处请替换成您的AccessKeySecret
        SecretKey key = new SecretKeySpec((secret + SEPARATOR).getBytes(ENCODE_TYPE), SignatureMethod.HMAC_SHA1);
        Mac mac = Mac.getInstance(ALGORITHM);
        mac.init(key);
        String signature = URLEncoder.encode(new String(
                new org.apache.commons.codec.binary.Base64().encode(mac.doFinal(stringToSign.toString().getBytes(ENCODE_TYPE))),
                ENCODE_TYPE), ENCODE_TYPE);
        // 生成请求URL
        StringBuilder requestURL;
        requestURL = new StringBuilder("http://mts." + aliOssConfig.getRegion() + ".aliyuncs.com?");
        requestURL.append(URLEncoder.encode("Signature", ENCODE_TYPE)).append("=").append(signature);
        for (Map.Entry<String, String> e : parameterMap.entrySet()) {
            requestURL.append("&").append(percentEncode(e.getKey())).append("=").append(percentEncode(e.getValue()));
        }

        return requestURL.toString();
    }

    /**
     * 查询视频转码成功后的信息，根据阿里转码回调信息中的MediaId
     *
     * @param runId
     * @return
     */
    public JSONObject queryVideoInfo(String mediaId) {
        JSONObject info = null;
        String path = null;
        StringBuilder sb = new StringBuilder();

        try {
            path = this.generateVideoQueryURL(mediaId);
        } catch (UnsupportedEncodingException e) {
            path = "";
        } catch (NoSuchAlgorithmException e) {
            path = "";
        } catch (InvalidKeyException e) {
            path = "";
        }

        try {
            URL url = new URL(path);
            URLConnection urlConnection = url.openConnection();
            urlConnection.connect();
            Scanner in = new Scanner(urlConnection.getInputStream());
            while (in.hasNextLine()) {
                sb.append(in.nextLine());
            }
            info = JSONObject.fromObject(sb.toString());
        } catch (MalformedURLException e) {
            info = new JSONObject();
        } catch (IOException e) {
            info = new JSONObject();
        }

        return info;
    }

    /**
     * 生成sts临时访问ak
     * {@link https://help.aliyun.com/document_detail/32016.html?spm=5176.doc32008.6.658.8uKDoR}
     *
     * @param bucketType 0 图片  1 视频
     * @return
     */
    public Map generateSts(int bucketType) {
        Map<String, String> responseMap = new LinkedHashMap<>();
        try {
            IClientProfile profile = DefaultProfile.getProfile(aliOssConfig.getRegion(), aliOssConfig.getAccessKeyId(), aliOssConfig.getAccessKeySecret());
            DefaultAcsClient client = new DefaultAcsClient(profile);

            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setVersion(STS_API_VERSION);
            request.setMethod(MethodType.POST);
            request.setProtocol(ProtocolType.HTTPS);
            request.setDurationSeconds(3600L);
            request.setRoleArn(aliOssConfig.getRoleArm());
            request.setRoleSessionName(aliOssConfig.getRoleSessionName());

            final AssumeRoleResponse response = client.getAcsResponse(request);
            responseMap.put("expire", response.getCredentials().getExpiration());
            responseMap.put("accessid", response.getCredentials().getAccessKeyId());
            responseMap.put("accesskey", response.getCredentials().getAccessKeySecret());
            responseMap.put("token", response.getCredentials().getSecurityToken());
            responseMap.put("bucketName", getBucketName(bucketType));
            responseMap.put("endpoint", aliOssConfig.getEndpoint());

        } catch (ClientException e) {
            e.printStackTrace();
        }
        return responseMap;
    }

    /**
     * 删除单个文件
     * {@link https://help.aliyun.com/document_detail/32015.html?spm=5176.doc32008.6.657.BEoXvs}
     *
     * @param bucketName
     * @param deleteObject
     */
    public void delete(String bucketName, String deleteObject) {
        OSSClient ossClient = new OSSClient(aliOssConfig.getEndpoint(), aliOssConfig.getAccessKeyId(), aliOssConfig.getAccessKeySecret());
        ossClient.deleteObject(bucketName, deleteObject);
        ossClient.shutdown();
    }

    /**
     * 批量删除
     * {@link https://help.aliyun.com/document_detail/32015.html?spm=5176.doc32008.6.657.BEoXvs}
     *
     * @param bucketName
     * @param keys
     */
    public void deleteList(String bucketName, List<String> keys) {
        OSSClient ossClient = new OSSClient(aliOssConfig.getEndpoint(), aliOssConfig.getAccessKeyId(), aliOssConfig.getAccessKeySecret());
        DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(keys));
        ossClient.shutdown();
    }

    /**
     * 通过bucketType 获取 bucket name
     *
     * @param bucketType
     * @return
     */
    private String getBucketName(int bucketType) {
        if (bucketType == 0) {
            return aliOssConfig.getImageBucketName();
        } else if (bucketType == 1) {
            return aliOssConfig.getVideoBucketName();
        }
        return aliOssConfig.getImageBucketName();
    }

    //public static void main(String[] args) {
    //    String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
    //    String accessKeyId = "LTAIJWU1gYbVZANx";
    //    String accessKeySecret = "MppfnHMA7LaokAUnvJsaYRnSpEj4wW";
    //    String bucketName = "dms-server";
    //
    //    OSSClient client = new OSSClient(endpoint, accessKeyId, accessKeySecret);
    //
    //
    //    //ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
    //    //listObjectsRequest.setPrefix("videosource/");
    //    //ObjectListing listing = client.listObjects(listObjectsRequest);
    //    //
    //    //for (OSSObjectSummary objectSummary : listing.getObjectSummaries()){
    //    //    System.out.println(objectSummary.getKey());
    //    //}
    //
    //    client.deleteObject("dms-server", "videosource/2Y7TnKTQ5P.mp4");
    //
    //}

}
